package group

import (
	"context"
	"fmt"
	"gitee.com/chunanyong/zorm"
	"gitee.com/xinshortlink/internal/constants"
	"gitee.com/xinshortlink/internal/dal/db/dao"
	"gitee.com/xinshortlink/internal/dal/db/model"
	"gitee.com/xinshortlink/internal/dto/resp/bizerr"
	"gitee.com/xinshortlink/internal/pkg/idgenerater"
	"gitee.com/xinshortlink/internal/pkg/token"
	"go.uber.org/zap"
	"time"
)

type Service struct {
	logger    *zap.Logger
	dao       *dao.GroupDao
	idGen     *idgenerater.IdGenerate
	loginUtil *token.LoginAccountUtil
}

func NewService(logger *zap.Logger, dao *dao.GroupDao, loginUtil *token.LoginAccountUtil, idGen *idgenerater.IdGenerate) *Service {
	return &Service{
		logger:    logger,
		dao:       dao,
		idGen:     idGen,
		loginUtil: loginUtil,
	}
}

func (s *Service) Create(ctx context.Context, name string) error {
	account := s.loginUtil.CurrentAccount(ctx)
	if account == nil {
		return bizerr.ErrTokenInvalid
	}

	count, err := s.dao.FindGroupCountByAccountName(ctx, account.AccountName)
	if err != nil {
		return fmt.Errorf("SERVICE: Create Group fail %w", err)
	}

	if count > 10 {
		return bizerr.ErrGroupOutOfRange
	}

	gid, err := s.idGen.GetId()
	if err != nil {
		return fmt.Errorf("SERVICE: Create Group fail %w", err)
	}

	_, err = zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		return nil, s.dao.Create(ctx, &model.GroupStruct{
			AccountName: account.AccountName,
			Gid:         gid,
			Name:        name,
			CreateTime:  time.Now(),
			UpdateTime:  time.Now(),
			DelState:    constants.NO,
		})
	})

	if err != nil {
		return fmt.Errorf("SERVICE: Create Group fail %w", err)
	}

	return nil
}

func (s *Service) Groups(ctx context.Context) ([]*model.GroupStruct, error) {
	account := s.loginUtil.CurrentAccount(ctx)
	if account == nil {
		return nil, bizerr.ErrTokenInvalid
	}

	g, err := s.dao.FindGroupByAccountName(ctx, account.AccountName)
	if err != nil {
		return nil, fmt.Errorf("SERVICE: Groups fail %w", err)
	}

	return g, nil
}

func (s *Service) Update(ctx context.Context, id int64, name string) error {
	err := s.checkUpdate(ctx, id)
	if err != nil {
		return fmt.Errorf("SERVICE: Update Group fail %w", err)
	}

	_, err = zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		return nil, s.dao.Update(ctx, &model.GroupStruct{
			Id:         id,
			Name:       name,
			UpdateTime: time.Now(),
		})
	})

	if err != nil {
		return fmt.Errorf("SERVICE: Update Group fail %w", err)
	}

	return nil
}

func (s *Service) checkUpdate(ctx context.Context, id int64) error {
	account := s.loginUtil.CurrentAccount(ctx)
	if account == nil {
		return bizerr.ErrTokenInvalid
	}

	g, err := s.dao.FindGroupById(ctx, id)

	if err != nil {
		return fmt.Errorf("SERVICE: checkUpdate fail %w", err)
	}

	if g == nil {
		return bizerr.ErrGroupNotFound
	}

	if g.AccountName != account.AccountName {
		return bizerr.ErrGroupNotPower
	}

	return nil
}

func (s *Service) Del(ctx context.Context, id int64) error {
	err := s.checkUpdate(ctx, id)
	if err != nil {
		return fmt.Errorf("SERVICE: Del Group fail %w", err)
	}

	_, err = zorm.Transaction(ctx, func(ctx context.Context) (interface{}, error) {
		return nil, s.dao.Update(ctx, &model.GroupStruct{
			Id:       id,
			DelTime:  time.Now(),
			DelState: constants.YES,
		})
	})

	if err != nil {
		return fmt.Errorf("SERVICE: Del Group fail %w", err)
	}

	return nil
}
